package com.aspire.nm.component.cmppserver.runTime.moProcess;

import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;

import javax.annotation.Resource;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.stereotype.Component;

import com.aspire.nm.component.cmppserver.filter.coder.packet.CmppDeliverPacket;
import com.aspire.nm.component.cmppserver.runTime.Connection;
import com.aspire.nm.component.cmppserver.runTime.SysRunTimeService;
import com.aspire.nm.component.cmppserver.util.InvokeRateUtil;
import com.aspire.nm.component.cmppserver.util.LogService;
import com.aspire.nm.component.cmppserver.util.MessageIdGenerator;
import com.aspire.nm.component.commonUtil.seq.SequenceGenerator;

@Scope("prototype")
@Component
public class MoSender extends ApplicationObjectSupport implements InitializingBean,Runnable{
	
	@Value("${cmppserver.moRetryTimeOut}")
	private int moRetryTimeOut;
	
	@Value("${cmppserver.maxDeliveryRetryHtSize}")
	private int maxDeliveryRetryHtSize;
	
	@Value("${cmppserver.deliveryRetry}")
    private boolean deliveryRetry;
	
	@Resource
    private LogService logService;
	
	@Resource
    private SysRunTimeService sysRunTimeService;
	
	
	private Timer timer;
	private Hashtable<Integer, TimerTask> deliveryRetryHt;
	
	private Thread t;
	public Thread getT(){
	    return t;
	}
	@Override
	public void afterPropertiesSet() throws Exception {
	    if(deliveryRetry){
	        timer = new Timer();
	        deliveryRetryHt = new Hashtable<Integer, TimerTask>();
	    }
	    t = new Thread(this);
	    t.start();
	}
	
	
	
	
	private Connection connection;
	public Connection getConnection() {
		return connection;
	}
	public void setConnection(Connection connection) {
		this.connection = connection;
	}
	
	
	
	
	
	
    public Timer getTimer() {
        return timer;
    }
	public Hashtable<Integer, TimerTask> getDeliveryRetryHt() {
		return deliveryRetryHt;
	}
	public void run(){
		
		SequenceGenerator seq = SequenceGenerator.getSequenceGenerator(1, Integer.MAX_VALUE);
		MessageIdGenerator msgIdGen = MessageIdGenerator.getMessageIdGenerator();
		
		try{
			while(!t.isInterrupted()){
				if(t.isInterrupted()) break;
				
				if(connection == null){
					Thread.sleep(5000);
					continue;
				}
				if(!connection.isMoConn()){
					break;
				}
				if(deliveryRetryHt != null && deliveryRetryHt.size() >= maxDeliveryRetryHtSize){
					continue;
				}
				
				CmppDeliverPacket pk = connection.getUserRunTime().getmOQueue().take();

				if(pk.autoDeliverSubmitTime != 0){
				    long tmp = System.currentTimeMillis() - pk.autoDeliverSubmitTime;
				    if(tmp < 1000){
				        Thread.sleep(1000 - tmp);
				    }
				}
				
				pk.setSequenceId(seq.nextInt());
				pk.setMsgId(msgIdGen.getMsgId((short)0));
				pk.setVersion(connection.getVersion());
				
				if(timer != null){
				    MoRetryTask moRetryTask = getApplicationContext().getBean(MoRetryTask.class);
	                moRetryTask.setmOSender(this);
	                moRetryTask.setPk(pk);
	                deliveryRetryHt.put(pk.getSequenceId(), moRetryTask);
	                timer.schedule(moRetryTask, moRetryTimeOut * 1000, moRetryTimeOut * 1000);
				}
				
				
				if(connection.getSession().isClosing()){
					throw new InterruptedException("Session is closed.");
				}else{
					if(pk.isSMSReport()){
					    sysRunTimeService.getMoMtCounter().getReportCounter().increment();
					    connection.getUserRunTime().getMoMtCounter().getReportCounter().increment();
						connection.getMoMtCounter().getReportCounter().increment();
					}else{
					    sysRunTimeService.getMoMtCounter().getMoCounter().increment();
					    connection.getUserRunTime().getMoMtCounter().getReportCounter().increment();
						connection.getMoMtCounter().getMoCounter().increment();
					}
					
					
					logService.deliver(connection.getUserRunTime().getUser(), pk);
					
					connection.getSession().write(pk);
					
					InvokeRateUtil.invokeRate_send_deliver.count();
				}
			}
		}catch(InterruptedException ex){
		    if(timer != null){
		        timer.cancel();
		        deliveryRetryHt.clear();
		    }
		}
	}
	
	
}
